#include "preport.h"

#include <QDebug>
#include "NumStr.h"

// Numero di caratteri per tabulazini predefinite
char PReport::            m_char_tab = ' ';
string PReport::m_objname_leftMark  = "[";
string PReport::m_objname_rightMark = "]";

// Valori predefiniti per conversione da campo numerico
unsigned int PReport::m_val_num_width_double = 6;
unsigned int PReport::   m_val_num_width_int = 3;
        char PReport::       m_val_num_align = 'R';
unsigned int PReport::   m_val_num_precision = 3;
        char PReport::      m_val_num_format = 'F';

// Valori predefiniti per conversione da campo stringa
unsigned int PReport::    m_val_str_width = 10;
        char PReport::    m_val_str_align = 'L';
      string PReport:: m_val_str_leftMark = "";
      string PReport::m_val_str_rightMark = "";
      string PReport::m_val_str_charTrunk = "";

// Valori predefiniti per conversione dei tag
unsigned int PReport::m_tag_width   = 0;
        char PReport::m_tag_align   = 'R';
      string PReport::m_tag_defMark = " = ";

string PReport::m_line = "";
PReport::tp_style PReport::m_style = PReport::STYLE_VERBOSE;

PReport::PReport( void )
{
    m_objname = "unknoun";
}

PReport::PReport( const string& objname ) :
    m_objname(objname)
{
}

void PReport::setReportOpt(const char *optname, bool opt_b)
{
    if (m_map_opt_b.count(optname) == 1)
        m_map_opt_b[optname]=opt_b;
}

void PReport::setReportOpt(const char *optname, string opt_s)
{
    if (m_map_opt_s.count(optname) == 1)
        m_map_opt_s[optname]=opt_s;
}

void PReport::setReportOpt(const char *optname, unsigned int opt_i)
{
    if (m_map_opt_i.count(optname) == 1)
        m_map_opt_i[optname]=opt_i;
}

void PReport::resetReportOpt ( void )
{
    // RESET DI BOOL OPTION
    m_map_opt_b ["null"] = false ; // parametro nullo
    m_map_opt_b [  "N" ] = true  ; // stampa N_ome oggetto
    m_map_opt_b [  "E" ] = true  ; // stampa E_nd del report
    m_map_opt_b [  "T" ] = true  ; // stampa T_abulazione
    m_map_opt_b [ "SUB"] = false ; // stampa come SUB_report

    // RESET DI UNSIGNED INT OPTION
    m_map_opt_i [  "T" ] =   1   ; // stampa n. T_abulazione
    m_map_opt_i [ "NT" ] =   4   ; // stampa Numero_di_T_abulazioni
}

const PReport&  PReport::report ( void ) const
{
    reportMake();
    resetReportStyle();
    return *this;
}

PReport& PReport::moveReportInCache( void )
{
    string tab = m_tab();

    list_report::iterator i;
    for (i=m_list_report.begin();i!=m_list_report.end();++i)
    {
        *i = tab + *i;
    }
    m_list_cache.splice(m_list_cache.end(),m_list_report);
    m_list_report.clear();
}

PReport& PReport::moveCacheInBlock( void )
{
    m_list_block.splice(m_list_block.end(),m_list_cache);
    m_list_cache.clear();
}

void PReport::reportMake(const string& objname) const
{
    string name;
    if (!objname.empty())
        name = m_objname_leftMark + objname + m_objname_rightMark;
    else
        name = m_objname_leftMark + m_objname + m_objname_rightMark;

    if (!objname.empty() && m_style == STYLE_JOURNAL)
        name = name + " [J]";

    string tab = m_tab();
    if (m_map_opt_b["SUB"] == true)
    {
        if (m_map_opt_b["N"] == true)
        {
            m_list_block.push_front(name);
            m_list_block.push_back(name);
        }
        list_report::iterator i;
        for (i=m_list_block.begin();i!=m_list_block.end();++i)
        {
            *i = tab + *i;
        }
        m_list_report.splice(m_list_report.end(),m_list_block);
    }
    else
    {
        if (m_map_opt_b["N"] == true)
            m_list_report.push_front(name);

        m_list_report.splice(m_list_report.end(),m_list_block);

        if (m_map_opt_b["N"] == true)
            m_list_report.push_back(name);
    }
    m_list_block.clear();
}


string  PReport::flushReportToStr ( void )
{
    string flush = "";
    list_report::const_iterator i;
    for (i = m_list_report.begin(); i!=m_list_report.end(); ++i)
    {
        flush += *i+"\n";
    }
    m_list_report.clear();
    return flush;
}

string  PReport::reportToString ( void )
{
    string flush = "";
    list_report::const_iterator i;
    for (i = m_list_report.begin(); i!=m_list_report.end(); ++i)
    {
        flush += *i+"\n";
    }
    return flush;
}

string  PReport::blockToString ( void )
{
    string flush = "";
    list_report::const_iterator i;
    for (i = m_list_block.begin(); i!=m_list_block.end(); ++i)
    {
        flush += *i+"\n";
    }
    return flush;
}

PReport::map_opt_b PReport::m_map_opt_b = PReport::m_init_opt_b();
PReport::map_opt_b PReport::m_init_opt_b(void)
{
    map_opt_b ref;
    ref ["null" ] = false; // parametro nullo
    ref [  "N"  ] = true;  // stampa N_ome oggetto
    ref [  "E"  ] = true;  //
    ref [  "T"  ] = true;  // stampa T_abulazione
    ref [ "SUB" ] = false; // stampa come SUB_report
    return ref;
}

PReport::map_opt_s PReport::m_map_opt_s = PReport::m_init_opt_s();
PReport::map_opt_s PReport::m_init_opt_s(void)
{
    map_opt_s ref;
    ref["null"]="";
    return ref;
}

PReport::map_opt_i PReport::m_map_opt_i = PReport::m_init_opt_i();
PReport::map_opt_i PReport::m_init_opt_i(void)
{
    map_opt_i ref;
    ref ["null"] = 0;
    ref [  "T" ] = 1; // stampa T_abulazione di 1 tab
    ref [ "NT" ] = 4; // stampa Numero_di_T_abulazioni
    return ref;
}

PReport::list_report PReport::m_list_block = PReport::m_init_list_report();
PReport::list_report PReport::m_list_report = PReport::m_init_list_report();
PReport::list_report PReport::m_list_cache = PReport::m_init_list_report();

PReport::list_report PReport::m_init_list_report(void)
{
    list_report l;
    return l;
}

void PReport::addInLine( const string& str )
{
    m_line.append(str);
}

void PReport::addInLine( const string& tag_name, const int& int_val, unsigned int width )
{
    unsigned int old_width = m_val_str_width;
    setReportStrWidth(width);
    addInLine( tag_name, int_val );
    setReportStrWidth(old_width);
}

void PReport::addInLine( const string& tag_name, const int& int_val )
{
    NumStr::tpAlign align_tag;
    if (m_tag_align == 'L')
        align_tag = NumStr::A_LEFT;
    if (m_tag_align == 'R')
        align_tag = NumStr::A_RIGHT;

    NumStr numstr_tag = NumStr(m_tag_width,align_tag,0,NumStr::F_FIXED);
    string tag_str = numstr_tag.conv(tag_name);

    NumStr::tpAlign align_val;
    if (m_val_num_align == 'L')
        align_val = NumStr::A_LEFT;
    if (m_val_num_align == 'R')
        align_val = NumStr::A_RIGHT;

    NumStr numstr_val = NumStr(m_val_num_width_int,align_val,0,NumStr::F_FIXED);
    string value_str = numstr_val.conv(int_val);

    m_line.append(tag_str + m_tag_defMark + value_str + " ");
}

void PReport::addInLine( const string& tag_name,
                       const double& double_val,
                       unsigned int width,
                       unsigned int prec
                       )
{
    unsigned int old_width = m_val_num_width_double;
    unsigned int old_prec  = m_val_num_precision;
    setReportNum(width,m_val_num_align,prec,m_val_num_format);
    addInLine(tag_name, double_val);
    setReportNum(old_width,m_val_num_align,old_prec,m_val_num_format);
}

void PReport::addInLine( const string& tag_name, const double& double_val )
{
    NumStr::tpAlign align_val;
    if (m_val_num_align == 'L')
        align_val = NumStr::A_LEFT;
    if (m_val_num_align == 'R')
        align_val = NumStr::A_RIGHT;

    NumStr::tpFormat format_val;
    if (m_val_num_format == 'F')
        format_val = NumStr::F_FIXED;
    if (m_val_num_format == 'S')
        format_val = NumStr::F_SCIENTIFIC;

    NumStr numstr_val = NumStr(m_val_num_width_double,align_val,m_val_num_precision,format_val);
    string value_str = numstr_val.conv(double_val);

    NumStr::tpAlign align_tag;
    if (m_tag_align == 'L')
        align_tag = NumStr::A_LEFT;
    if (m_tag_align == 'R')
        align_tag = NumStr::A_RIGHT;

    NumStr numstr_tag = NumStr(m_tag_width,align_tag,0,NumStr::F_FIXED);
    string tag_str = numstr_tag.conv(tag_name);

    m_line.append(tag_str + m_tag_defMark + value_str + " ");
}

void PReport::addInLine( const string& tag_name, const bool& bool_val )
{
    NumStr::tpAlign align_val;
    if (m_val_num_align == 'L')
        align_val = NumStr::A_LEFT;
    if (m_val_num_align == 'R')
        align_val = NumStr::A_RIGHT;

    NumStr numstr_val = NumStr(m_val_num_width_double,align_val,0,NumStr::F_FIXED);
    string val_str = numstr_val.conv(bool_val);

    NumStr::tpAlign align_tag;
    if (m_tag_align == 'L')
        align_tag = NumStr::A_LEFT;
    if (m_tag_align == 'R')
        align_tag = NumStr::A_RIGHT;

    NumStr numstr_tag = NumStr(m_tag_width,align_tag,0,NumStr::F_FIXED);
    string tag_str = numstr_tag.conv(tag_name);

    m_line.append(tag_str + m_tag_defMark + val_str + " ");
}

void PReport::setReportStrWidth( unsigned int width )
{
    m_val_str_width = width;
}

void PReport::addInLine( const string& tag_name,
                           const string& string_val,
                           unsigned int width
                         )
{
    unsigned int old_width = m_val_str_width;
    setReportStrWidth(width);
    addInLine( tag_name, string_val );
    setReportStrWidth(old_width);
}

void PReport::addInLine( const string& tag_name, const string& string_val )
{
    NumStr::tpAlign align_val;
    if (m_val_str_align == 'L')
        align_val = NumStr::A_LEFT;
    if (m_val_str_align == 'R')
        align_val = NumStr::A_RIGHT;

    NumStr numstr_val = NumStr(m_val_str_width,align_val,0,NumStr::F_FIXED);
    string val_str = numstr_val.conv(string_val,m_val_str_charTrunk);

    NumStr::tpAlign align_tag;
    if (m_tag_align == 'L')
        align_tag = NumStr::A_LEFT;
    if (m_tag_align == 'R')
        align_tag = NumStr::A_RIGHT;

    NumStr numstr_tag = NumStr(m_tag_width,align_tag,0,NumStr::F_FIXED);
    string tag_str = numstr_tag.conv(tag_name);

    m_line.append(tag_str + m_tag_defMark +
                  m_val_str_leftMark + val_str + m_val_str_rightMark + " ");
}

void PReport::setReportNum(
                unsigned int width,
                        char align,
                unsigned int prec,
                        char format
                               )
{
    m_val_num_width_double     = width;
    if (align == 'L' || align == 'R')
        m_val_num_align     = align;
    m_val_num_precision = prec;
    if (format == 'F' || format == 'S')
        m_val_num_format    = format;
}

void PReport::setReportNumWidth( unsigned int width )
{
    m_val_num_width_double = width;
}

void PReport::setReportNumFormat( char format )
{
    if (format == 'F' || format == 'S')
        m_val_num_format    = format;
}

void PReport::resetReportNum ( void )
{
    m_val_num_width_double =  6  ;
           m_val_num_align = 'L' ;
       m_val_num_precision =  3  ;
          m_val_num_format = 'F' ;
}

void PReport::setReportStr(
                unsigned int width,
                        char align,
                       const string& left_mark,
                       const string& right_mark,
                       const string& char_trunk
                               )
{
    m_val_str_width     = width;
    if (align == 'L' || align == 'R')
        m_val_str_align     = align;
    m_val_str_leftMark  = left_mark;
    m_val_str_rightMark = right_mark;
    m_val_str_charTrunk = char_trunk;
}

void PReport::resetReportStr( void )
{
    m_val_str_width     = 10;
    m_val_str_align     = 'L';
    m_val_str_leftMark  = "";
    m_val_str_rightMark = "";
    m_val_str_charTrunk = "";
}

void PReport::setReportTag(
                unsigned int width,
                        char align,
                       const string& def_mark
                               )
{
    m_tag_width   = width;
    if (align == 'L' || align == 'R')
        m_tag_align  = align;
    m_tag_defMark = def_mark;
}

void PReport::resetReportTag( void )
{
    m_tag_width   = 0;
    m_tag_align  = 'R';
    m_tag_defMark = " = ";
}

PReport& PReport::addLineInReport( const string& back_line )
{
    string tab = m_tab();
    m_list_report.push_back(tab + back_line);
}

PReport& PReport::moveLineInBlock( bool ins_tab )
{
    string tab = m_tab();
    if (!m_line.empty())
    {
        if (ins_tab == false)
        {
            m_list_block.push_back(tab + m_line);
        }
        else
        {
            size_t pos = 0;
            string    str = m_line; // stringa da modificare
            string oldStr = "\n"; // stringa originaria
            string newStr = "\n" + tab ;
            while((pos = str.find(oldStr, pos)) != std::string::npos)
            {
               str.replace(pos, oldStr.length(), newStr);
               pos += newStr.length();
            }
            m_list_block.push_back(tab + str);
        }
    }
    m_line.clear();
}

PReport& PReport::moveLineInBlock( void )
{
    string tab = m_tab();
    if (!m_line.empty())
    {
        m_list_block.push_back(tab + m_line);
    }
    m_line.clear();
}

PReport& PReport::moveLineInBlock( const string& back_line)
{
    string tab = m_tab();
    if (!back_line.empty())
    {
        m_list_block.push_back(tab + back_line);
    }
    moveLineInBlock();
}

PReport& PReport::moveLineInBlock( const string& back_line, const string &front_line )
{
    string tab = m_tab();
    if (!back_line.empty())
    {
        m_list_block.push_back(tab + back_line);
    }
    if (!front_line.empty())
    {
        m_list_block.push_front(tab + front_line);
    }
    moveLineInBlock();
}

PReport& PReport::lineNested( void )
{
    list_report::iterator i = m_list_block.end();
    --i;
    string old = *i;
    *i = m_tab() + old;
}

string PReport::m_tab(void)
{
    string tab = "";
    if (m_map_opt_b["T"] == true)
        tab += string(m_map_opt_i["NT"]*m_map_opt_i["T"],m_char_tab);
    return tab;
}

const PReport&  PReport::reportStyle ( const tp_style& sty ) const
{
    setReportStyle(sty);
    return *this;
}

void PReport::setReportStyle( const tp_style& sty )
{
    m_style = sty;
}

void PReport::resetReportStyle( void )
{
    m_style = STYLE_VERBOSE;
}

PReport::tp_style PReport::getReportCurrentStyle( void )
{
    return m_style;
}

string PReport::reportAndFlushToStr ( void ) const
{
    return report().flushReportToStr();
}

string  PReport::journalAndFlushToStr ( void ) const
{
    reportStyle(PReport::STYLE_JOURNAL);
    return report().flushReportToStr();
}

